๊ณ ์ฑ๋ฅ ์ค์๊ฐ ์ ํ๋ฆฌ์ผ์ด์ ๊ตฌ์ถ์ ์ํ FastAPI์ ๊ฐ๋ ฅํ WebSocket ๊ธฐ๋ฅ ํ์. ์ค์ฉ์ ์ธ ์์ ์ ๋ชจ๋ฒ ์ฌ๋ก๋ฅผ ํตํด ๊ธ๋ก๋ฒ ์ฌ์ฉ์ ๊ธฐ๋ฐ์ ์ํ ์ฑํ , ๋ผ์ด๋ธ ๋์๋ณด๋, ํ์ ๋๊ตฌ ๊ตฌํ ๋ฐฉ๋ฒ์ ์์๋ด ๋๋ค.
FastAPI WebSocket ์ง์: ๊ธ๋ก๋ฒ ์ฌ์ฉ์๋ฅผ ์ํ ์ค์๊ฐ ํต์
์ ์ ๋ ์ํธ ์ฐ๊ฒฐ๋๋ ์ธ์์์ ์ฆ๊ฐ์ ์ธ ์ ๋ณด์ ์ํํ ์ํธ ์์ฉ์ ๋ํ ์๊ตฌ๋ ์ง๋ฆฌ์ ๊ฒฝ๊ณ๋ฅผ ์์ง ๋ชปํฉ๋๋ค. ํ๋ ์น ์ ํ๋ฆฌ์ผ์ด์ ์ ๋ ์ด์ ์ ์ ํ์ด์ง๋ ์ฃผ๊ธฐ์ ์ธ ๋ฐ์ดํฐ ์๋ก๊ณ ์นจ์ ๋ง์กฑํ์ง ์์ต๋๋ค. ์ฌ์ฉ์๋ ๋๋ฅ ๊ฐ ๋๋ฃ์ ๋ฌธ์๋ฅผ ๊ณต๋ ์์ ํ๋ , ๊ธ์ต ์์ฅ์ ์ถ์ ํ๋ , ๋ค๋ฅธ ์๊ฐ๋์ ์น๊ตฌ์ ์ฑํ ํ๋ ์ค์๊ฐ ๊ฒฝํ์ ๊ธฐ๋ํฉ๋๋ค. ์ฆ๊ฐ์ฑ์ ํฅํ ์ด๋ฌํ ๊ทผ๋ณธ์ ์ธ ๋ณํ๋ก ์ธํด ์ค์๊ฐ ํต์ ์ ์ ์ธ๊ณ์ ์ผ๋ก ๋งค๋ ฅ์ ์ธ ์ฌ์ฉ์ ๊ฒฝํ์ ์ด์์ด ๋์์ต๋๋ค.
์ด๋ฌํ ์ค์๊ฐ ์ํธ ์์ฉ์ ์ค์ฌ์๋ WebSockets๊ฐ ์์ต๋๋ค. ์ด๋ ๋จ์ผ TCP ์ฐ๊ฒฐ์ ํตํด ์ ์ด์ค ํต์ ์ฑ๋์ ํ์ฑํํ๋ ๊ฐ๋ ฅํ ํ๋กํ ์ฝ์ ๋๋ค. ๊ธฐ์กด HTTP์ ์์ฒญ-์๋ต ๋ชจ๋ธ๊ณผ ๋ฌ๋ฆฌ WebSockets๋ฅผ ์ฌ์ฉํ๋ฉด ํด๋ผ์ด์ธํธ์ ์๋ฒ ๋ชจ๋ ์ธ์ ๋ ์ง ์๋ก ๋ฉ์์ง๋ฅผ ๋ณด๋ผ ์ ์์ผ๋ฏ๋ก ๋ฐ๋ณต์ ์ธ ์ฐ๊ฒฐ ์ค์ ์ค๋ฒํค๋๋ฅผ ์ ๊ฑฐํ๊ณ ํจ์ฌ ๋ฎ์ ์ง์ฐ ์๊ฐ์ ์ ๊ณตํฉ๋๋ค. ์ด ์ง์์ ์ด๊ณ ์๋ฐฉํฅ ์ฐ๊ฒฐ์ ์ค์๊ฐ ์ฑํ , ์จ๋ผ์ธ ๊ฒ์, ๊ณต๋ ํธ์ง ๋ฐ ์ฆ์ ์ ๋ฐ์ดํธ๋๋ ๋์ ๋์๋ณด๋๋ฅผ ์ง์ํ๋ ๊ฒ์ ๋๋ค.
FastAPI๋ Python 3.7+๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ํ์ค Python ํ์ ํํธ๋ฅผ ์ฌ์ฉํ์ฌ API๋ฅผ ๊ตฌ์ถํ๋ ํ๋์ ์ด๊ณ ๋น ๋ฅธ(๊ณ ์ฑ๋ฅ) ์น ํ๋ ์์ํฌ์ ๋๋ค. ์น ๋ถ๋ถ์ Starlette์, ๋ฐ์ดํฐ ๊ฒ์ฆ ๋ฐ ์ง๋ ฌํ๋ Pydantic์ ๊ธฐ๋ฐํ FastAPI๋ ๊ฐ๋ ฅํ ์น ์ ํ๋ฆฌ์ผ์ด์ ์ ๊ฐ๋ฐํ ์ ์๋ ๋งค์ฐ ์ง๊ด์ ์ด๊ณ ํจ์จ์ ์ธ ๋ฐฉ๋ฒ์ ์ ๊ณตํฉ๋๋ค. ์ค์ํ๊ฒ๋ ๋น๋๊ธฐ ํน์ฑ๊ณผ Starlette์์ ๊น์ ํตํฉ์ FastAPI๊ฐ WebSockets์ ๋ํ ์ต์ฐ์ ์ง์์ ์ ๊ณตํ๋ค๋ ๊ฒ์ ์๋ฏธํ๋ฉฐ, ์ด๋ ๊ธ๋ก๋ฒ ์ฌ์ฉ์ ๊ธฐ๋ฐ์ ์๊ตฌ๋ฅผ ์ถฉ์กฑํ๋๋ก ํ์ฅ ๊ฐ๋ฅํ ์ค์๊ฐ ํต์ ์๋ฃจ์ ์ ๋ง๋๋ ๋ฐ ํ์ํ ์ ํ์ ๋๋ค.
์ด ํฌ๊ด์ ์ธ ๊ฐ์ด๋์์๋ FastAPI์ WebSocket ๊ธฐ๋ฅ์ ์ดํด๋ณด๊ณ ์ค์๊ฐ ๊ธฐ๋ฅ ๊ตฌ์ถ ๊ณผ์ ์ ์๋ดํฉ๋๋ค. ์ค์ฉ์ ์ธ ์์ ๋ฅผ ํ์ํ๊ณ , ๊ธ๋ก๋ฒ ๋ฐฐํฌ๋ฅผ ์ํ ์ํคํ ์ฒ ๊ณ ๋ ค ์ฌํญ์ ๋ ผ์ํ๋ฉฐ, ์ ํ๋ฆฌ์ผ์ด์ ์ด ์ ์ธ๊ณ ์ฌ์ฉ์์๊ฒ ์ฑ๋ฅ์ด ๋ฐ์ด๋๊ณ ํ์ฅ ๊ฐ๋ฅํ๋ฉฐ ์์ ํ์ง ํ์ธํ๊ธฐ ์ํ ๋ชจ๋ฒ ์ฌ๋ก๋ฅผ ๊ฐ์กฐํ ๊ฒ์ ๋๋ค.
์ค์๊ฐ์ ๋ฐฑ๋ณธ์ธ WebSocket ์ดํดํ๊ธฐ
FastAPI์ ํน์ ์ฌํญ์ ์ดํด๋ณด๊ธฐ ์ ์ WebSocket์ ๋ํ ์ดํด๋ฅผ ํ๊ณ ํ ํ๊ณ ์ค์๊ฐ ํต์ ์ ํ์์ ์ธ ์ด์ ๋ฅผ ์์๋ณด๊ฒ ์ต๋๋ค.
HTTP์์ WebSockets๋ก์ ์งํ
- HTTP์ ํ๊ณ: ๊ธฐ์กด HTTP(Hypertext Transfer Protocol)๋ ์ํ ๋น์ ์ฅ, ์์ฒญ-์๋ต ํ๋กํ ์ฝ์ ๋๋ค. ํด๋ผ์ด์ธํธ๊ฐ ์์ฒญ์ ๋ณด๋ด๊ณ ์๋ฒ๊ฐ ์๋ตํ ๋ค์ ์ฐ๊ฒฐ์ด ์ผ๋ฐ์ ์ผ๋ก ๋ซํ๋๋ค(๋๋ ์งง์ ์๊ฐ ๋์ ์ ์ง๋จ). ์ค์๊ฐ ์ ๋ฐ์ดํธ์ ๊ฒฝ์ฐ ์ด ๋ชจ๋ธ์ ํด๋ผ์ด์ธํธ๊ฐ ์๋ฒ์์ ์ ์ ๋ณด๋ฅผ ๋์์์ด "ํด๋ง"ํ๋๋ก ๊ฐ์ ํ์ฌ ๋นํจ์จ์ ์ธ ๋ฆฌ์์ค ์ฌ์ฉ, ์ฆ๊ฐ๋ ์ง์ฐ ์๊ฐ ๋ฐ ๋ถํ์ํ ๋คํธ์ํฌ ํธ๋ํฝ์ ์ด๋ํฉ๋๋ค. "๊ธด ํด๋ง"๊ณผ ๊ฐ์ ๊ธฐ์ ์ ์ด๋ฅผ ์ํํ์ง๋ง ์ง์ ํ ์๋ฐฉํฅ ํต์ ์ ์ ๊ณตํ์ง๋ ์์ต๋๋ค.
- WebSocket์ ํด๊ฒฐ์ฑ : WebSockets๋ ํด๋ผ์ด์ธํธ์ ์๋ฒ ๊ฐ์ ์ง์์ ์ด๊ณ ์ ์ด์ค ํต์ ์ฑ๋์ ์ค์ ํฉ๋๋ค. ์ฐ๊ฒฐ์ด ์ค์ ๋๋ฉด(์ด๊ธฐ HTTP ํธ๋์ ฐ์ดํฌ๋ฅผ ํตํด "์ ๊ทธ๋ ์ด๋"๋จ) ์์ชฝ ๋์ ์ฐ๊ฒฐ์ด ๋ช ์์ ์ผ๋ก ๋ซํ ๋๊น์ง ์ธ์ ๋ ์ง ๋ ๋ฆฝ์ ์ผ๋ก ๋ฐ์ดํฐ๋ฅผ ์๋ก ๋ณด๋ผ ์ ์์ต๋๋ค. ์ด๋ ๊ฒ ํ๋ฉด ์ง์ฐ ์๊ฐ๊ณผ ์ค๋ฒํค๋๊ฐ ํฌ๊ฒ ์ค์ด๋ค์ด ์ค์๊ฐ ์ํธ ์์ฉ์ด ์ฆ๊ฐ์ ์ผ๋ก ๋๊ปด์ง๋๋ค.
WebSocket์ ์ฃผ์ ์ด์
๋ค์ํ ๋๋ฅ์ ์ฌ์ฉ์์๊ฒ ์๋น์ค๋ฅผ ์ ๊ณตํ๋ ์ ํ๋ฆฌ์ผ์ด์ ์ ๊ฒฝ์ฐ WebSocket์ ์ด์ ์ด ํนํ ๋๋๋ฌ์ง๋๋ค.
- ๋ฎ์ ์ง์ฐ ์๊ฐ: ๊ฐ ๋ฉ์์ง์ ๋ํด ์ ์ฐ๊ฒฐ์ ์ค์ ํ๋ ์ค๋ฒํค๋ ์์ด ๋ฐ์ดํฐ๋ฅผ ๊ตํํ ์ ์์ผ๋ฉฐ, ์ด๋ ๋ฐ๋ฆฌ์ด๊ฐ ์ค์ํ ๊ธ์ต ๊ฑฐ๋ ๋๋ ์จ๋ผ์ธ ๊ฒ์๊ณผ ๊ฐ์ ์ ํ๋ฆฌ์ผ์ด์ ์ ์ค์ํฉ๋๋ค.
- ํจ์จ์ ์ธ ๋ฆฌ์์ค ์ฌ์ฉ: ์๋ง์ ๋จ๊ธฐ HTTP ์ฐ๊ฒฐ๋ณด๋ค ํ๋์ ์ฅ๊ธฐ ์ฐ๊ฒฐ์ด ๋ ํจ์จ์ ์ด์ด์ ์๋ฒ ๋ถํ์ ๋คํธ์ํฌ ํผ์ก์ ์ค์ ๋๋ค.
- ์๋ฐฉํฅ ํต์ : ์๋ฒ์ ํด๋ผ์ด์ธํธ ๋ชจ๋ ๋ฐ์ดํฐ ์ ์ก์ ์์ํ ์ ์์ด ์ง์ ํ ์ํธ ์์ฉ์ด ๊ฐ๋ฅํฉ๋๋ค. ์๋ฒ๋ ๋ฐ์ดํฐ๊ฐ ๋ฐ์ํ๋ ์ฆ์ ํด๋ผ์ด์ธํธ์ ์ ๋ฐ์ดํธ๋ฅผ "ํธ์"ํ ์ ์์ผ๋ฏ๋ก ํด๋ผ์ด์ธํธ๊ฐ ์ ๋ฐ์ดํฐ๋ฅผ ๋์์์ด ์์ฒญํ ํ์๊ฐ ์์ต๋๋ค.
- ํฌ๋ก์ค ํ๋ซํผ ํธํ์ฑ: WebSocket API๋ ํ์คํ๋์ด ์์ผ๋ฉฐ ๊ฑฐ์ ๋ชจ๋ ์ต์ ์น ๋ธ๋ผ์ฐ์ , ๋ชจ๋ฐ์ผ ์ด์ ์ฒด์ ๋ฐ ๋ง์ ํ๋ก๊ทธ๋๋ฐ ์ธ์ด์์ ์ง์๋๋ฏ๋ก ๊ธ๋ก๋ฒ ์ ํ๋ฆฌ์ผ์ด์ ์ ๊ด๋ฒ์ํ ๋๋ฌ ๋ฒ์๋ฅผ ๋ณด์ฅํฉ๋๋ค.
WebSocket์ผ๋ก ์ง์๋๋ ๊ธ๋ก๋ฒ ์ฌ์ฉ ์ฌ๋ก
WebSocket์ด ์ ์ธ๊ณ์ ์ผ๋ก ๋ฐ์ด๋ ์ฑ๋ฅ์ ๋ฐํํ๋ ์ค์ ์๋๋ฆฌ์ค๋ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
- ๊ณต๋ ๋ฌธ์ ํธ์ง: ๋ฐ๋, ๋ด์, ๋์ฟ์ ํผ์ ธ ์๋ ํ์ด ๋์์ ๋ฌธ์๋ฅผ ํธ์งํ๋ค๊ณ ์์ํด ๋ณด์ญ์์ค. WebSockets๋ ํ ์ฌ์ฉ์๊ฐ ๋ง๋ ๋ณ๊ฒฝ ์ฌํญ์ด ๋ค๋ฅธ ๋ชจ๋ ์ฌ์ฉ์์๊ฒ ์ฆ์ ๋ฐ์๋๋๋ก ํ์ฌ ์ํํ ๊ณต๋ ์์ ์ ์ด์งํฉ๋๋ค.
- ์ค์๊ฐ ์ฑํ ๋ฐ ๊ณ ๊ฐ ์ง์: ๋ง๋๋ผ์ ๊ณ ๊ฐ ์๋น์ค ๋ด๋น์๊ฐ ๋ฒ ๋ฅผ๋ฆฐ์ ์ฌ์ฉ์๋ฅผ ์ง์ํ๋ , ๊ธ๋ก๋ฒ ์ปค๋ฎค๋ํฐ๊ฐ ํ ๋ก ์ ์ฐธ์ฌํ๋ , WebSockets๋ ์ฆ๊ฐ์ ์ธ ๋ฉ์์ง ๋ฐฑ๋ณธ์ ์ ๊ณตํฉ๋๋ค.
- ๊ธ์ต ๊ฑฐ๋ ํ๋ซํผ: ์๋ก ๋ค๋ฅธ ๊ธ์ต ์ผํฐ์ ๊ฑฐ๋์๋ ์ ๋ณด์ ์ ๊ฐํ ๊ฒฐ์ ์ ๋ด๋ฆฌ๊ธฐ ์ํด ์ค์๊ฐ ์ฃผ๊ฐ ์ ๋ฐ์ดํธ์ ์ฆ๊ฐ์ ์ธ ์ฃผ๋ฌธ ํ์ธ์ด ํ์ํฉ๋๋ค.
- ์จ๋ผ์ธ ๊ฒ์: ๋ฉํฐํ๋ ์ด์ด ๊ฒ์์ ํ๋ ์ด์ด ๋์๊ณผ ๊ฒ์ ์ํ๋ฅผ ๋๊ธฐํํ๊ธฐ ์ํด ๋ฎ์ ์ง์ฐ ์๊ฐ ํต์ ์ ์์กดํ์ฌ ์ ์ธ๊ณ ์ฐธ๊ฐ์์๊ฒ ์ํํ ๊ฒฝํ์ ์ ๊ณตํฉ๋๋ค.
- IoT ๋์๋ณด๋: ์ ์ธ๊ณ์ ๋ฐฐํฌ๋ ์ฅ์น(์: ์ค๋งํธ ์ํฐ ์ธํ๋ผ, ์ฐ์ ๊ธฐ๊ณ)์ ์ผ์ ๋ฐ์ดํฐ๋ฅผ ๋ชจ๋ํฐ๋งํ๋ ค๋ฉด ์ค์ ๋์๋ณด๋๋ก์ ์ง์์ ์ด๊ณ ์ค์๊ฐ์ ์ธ ๋ฐ์ดํฐ ์คํธ๋ฆฌ๋ฐ์ด ํ์ํฉ๋๋ค.
- ๋ผ์ด๋ธ ์คํฌ์ธ ๋ฐ ์ด๋ฒคํธ ์ ๋ฐ์ดํธ: ์ ์ธ๊ณ ํฌ๋ค์ ๋ธ๋ผ์ฐ์ ๋ฅผ ์๋ก๊ณ ์นจํ ํ์ ์์ด ์ฆ๊ฐ์ ์ธ ์ ์, ํด์ค ๋ฐ ์ด๋ฒคํธ ์ํ ์ ๋ฐ์ดํธ๋ฅผ ๋ฐ์ ์ ์์ต๋๋ค.
FastAPI๊ฐ WebSocket ์ ํ๋ฆฌ์ผ์ด์ ์ ์ ํฉํ ์ด์
FastAPI์ ์ค๊ณ ์์น๊ณผ ๊ธฐ๋ณธ ๊ธฐ์ ์ ๊ฐ๋ ฅํ WebSocket ์ง์ ์๋น์ค๋ฅผ ๊ตฌ์ถํ๋ ๋ฐ ํ์ํ ์ ํ์ด๋ฉฐ, ํนํ ๊ธ๋ก๋ฒ ์ฌ์ฉ์ ๊ธฐ๋ฐ์ ๋์์ผ๋ก ํ ๋ ๊ทธ๋ ์ต๋๋ค.
์ค๊ณ์ ๋น๋๊ธฐ(async/await)
Python์ asyncio๋ FastAPI๊ฐ ์์ฒ ๊ฐ์ ๋์ ์ฐ๊ฒฐ์ ํจ์จ์ ์ผ๋ก ์ฒ๋ฆฌํ ์ ์๋๋ก ํฉ๋๋ค. ์ฐ๊ฒฐ์ด ์ค๋ ์ง์๋๊ณ ์๋ฒ๊ฐ ์ฌ๋ฌ ํด๋ผ์ด์ธํธ๋ก๋ถํฐ ๋์์ ๋ฉ์์ง๋ฅผ ๊ธฐ๋ค๋ ค์ผ ํ๋ WebSocket์ ๊ฒฝ์ฐ ๋น๋๊ธฐ ํ๋ ์์ํฌ๊ฐ ํ์์ ์
๋๋ค. FastAPI๋ async/await ๊ตฌ๋ฌธ์ ํ์ฉํ์ฌ ์ด๋ฒคํธ ๋ฃจํ๋ฅผ ์ฐจ๋จํ์ง ์๋ ๋งค์ฐ ๋์์ ์ธ ์ฝ๋๋ฅผ ์์ฑํ ์ ์๋๋ก ํ์ฌ ๋๋ฆฐ ํด๋ผ์ด์ธํธ ํ๋๊ฐ ๋ค๋ฅธ ํด๋ผ์ด์ธํธ์ ์ฑ๋ฅ์ ์ ํ์ํค์ง ์๋๋ก ํฉ๋๋ค.
์ฆ์ ์ฌ์ฉ ๊ฐ๋ฅํ ๊ณ ์ฑ๋ฅ
FastAPI๋ ๊ฒฝ๋ ASGI ํ๋ ์์ํฌ์ธ Starlette๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ํ๋ฉฐ ์ผ๋ฐ์ ์ผ๋ก ๋ฒ๊ฐ์ฒ๋ผ ๋น ๋ฅธ ASGI ์๋ฒ์ธ Uvicorn๊ณผ ํจ๊ป ์คํ๋ฉ๋๋ค. ์ด ์กฐํฉ์ Node.js ๋ฐ Go์ ๋๋ฑํ ๋ฐ์ด๋ ์ฑ๋ฅ์ ์ ๊ณตํ์ฌ ์ ์ญ์ ์ผ๋ก ํ์ฅ ๊ฐ๋ฅํ ์ ํ๋ฆฌ์ผ์ด์ ์ ์ค์ํ ๋๋์ ๋์ WebSocket ์ฐ๊ฒฐ๊ณผ ๋์ ๋ฉ์์ง ์ฒ๋ฆฌ๋์ ๊ด๋ฆฌํ ์ ์์ต๋๋ค.
๊ฐ๋ฐ์ ๊ฒฝํ ๋ฐ ์์ฐ์ฑ
- ์ง๊ด์ ์ธ API: FastAPI์ ๋ฐ์ฝ๋ ์ดํฐ ๊ธฐ๋ฐ ์ ๊ทผ ๋ฐฉ์์ WebSocket ์๋ํฌ์ธํธ๋ฅผ ์ ์ํ๋ ๋ฐ ๊น๋ํ๊ณ ์ดํดํ๊ธฐ ์ฝ์ต๋๋ค.
- Pydantic์ ์ฌ์ฉํ ์๋ ์ ํ ๊ฒ์ฆ: WebSocket์ ํตํด ๋ณด๋ด๊ณ ๋ฐ๋ ๋ฐ์ดํฐ๋ Pydantic ๋ชจ๋ธ์ ์ฌ์ฉํ์ฌ ์๋์ผ๋ก ๊ฒ์ฆ ๋ฐ ์ง๋ ฌํ๋ ์ ์์ต๋๋ค. ์ด๋ ๋ฐ์ดํฐ ๋ฌด๊ฒฐ์ฑ์ ๋ณด์ฅํ๊ณ ๋ณด์ผ๋ฌํ๋ ์ดํธ ์ฝ๋๋ฅผ ์ค์ฌ์ฃผ๋ฏ๋ก ๋ช ํํ ๋ฐ์ดํฐ ๊ณ์ฝ์ด ์คํด๋ฅผ ๋ฐฉ์งํ๋ ๋ค์ํ ๊ตญ์ ํ์ ํนํ ๊ฐ์น๊ฐ ์์ต๋๋ค.
- ๋ํํ API ๋ฌธ์: ์ฃผ๋ก HTTP API๋ฅผ ์ํ ๊ฒ์ด์ง๋ง FastAPI์ ์๋ OpenAPI/Swagger UI ๋ฌธ์๋ ํ์ด API ๊ตฌ์กฐ๋ฅผ ์ดํดํ๋ ๋ฐ ๋์์ด ๋๋ฉฐ, ๋ง์ฐฌ๊ฐ์ง๋ก WebSocket ํธ๋ค๋ฌ์ ๋ํ ํ์ ํํธ๋ ์์ ๋ฐ์ดํฐ ์ ํ์ ๋ช ํํ ํฉ๋๋ค.
- Python ํ์ ํํธ: Python์ ํ์ ํํธ๋ฅผ ํ์ฉํ๋ฉด ์ฝ๋ ๊ฐ๋ ์ฑ, ์ ์ง ๊ด๋ฆฌ์ฑ์ด ํฅ์๋๊ณ ์๋ ์์ฑ ๋ฐ ์ค๋ฅ ๊ฒ์ฌ์ ๊ฐ์ ๊ฐ๋ ฅํ IDE ๊ธฐ๋ฅ์ด ๊ฐ๋ฅํด์ ธ ์ง๋ฆฌ์ ์ผ๋ก ๋ถ์ฐ๋ ํ ๊ฐ์ ๊ฐ๋ฐ ๋ฐ ๋๋ฒ๊น ์ด ๊ฐ์ํ๋ฉ๋๋ค.
ASGI ํ์ค ์ค์
FastAPI๋ ๋น๋๊ธฐ ์๋ฒ ๊ฒ์ดํธ์จ์ด ์ธํฐํ์ด์ค(ASGI) ์ฌ์์ ์ค์ํฉ๋๋ค. ์ด๋ FastAPI ์ ํ๋ฆฌ์ผ์ด์ ์ Uvicorn ๋๋ Hypercorn์ ๊ฐ์ ๋ชจ๋ ASGI ํธํ ์๋ฒ์ ํจ๊ป ๋ฐฐํฌํ ์ ์์ผ๋ฉฐ ๋ค๋ฅธ ASGI ๋ฏธ๋ค์จ์ด ๋ฐ ๋๊ตฌ์ ์ฝ๊ฒ ํตํฉํ ์ ์์ด ๋ฐฐํฌ ์ํคํ ์ฒ์ ์ ์ฐ์ฑ์ ์ ๊ณตํฉ๋๋ค.
WebSocket์ฉ FastAPI ํ๋ก์ ํธ ์ค์
์ค์ฉ์ ์ผ๋ก ์ ๊ทผํด ๋ณด๊ฒ ์ต๋๋ค. ์์ํ๋ ค๋ฉด Python 3.7 ์ด์์ด ์ค์น๋์ด ์๋์ง ํ์ธํ์ญ์์ค. ๊ทธ๋ฐ ๋ค์ FastAPI์ Uvicorn์ ์ค์นํฉ๋๋ค.
pip install fastapi "uvicorn[standard]"
์ฒซ "Hello WebSocket" ์ ํ๋ฆฌ์ผ์ด์
FastAPI์์ ๊ธฐ๋ณธ WebSocket ์๋ํฌ์ธํธ๋ฅผ ๋ง๋๋ ๊ฒ์ ๊ฐ๋จํฉ๋๋ค. ๋ค์์ ์์ ํ๋ ๋ชจ๋ ๋ฉ์์ง๋ฅผ ๋ค์ ์์ฝํ๋ ๊ฐ๋จํ ์์ ์ ๋๋ค.
from fastapi import FastAPI, WebSocket, WebSocketDisconnect
app = FastAPI()
@app.websocket("/ws")
async def websocket_endpoint(websocket: WebSocket):
await websocket.accept()
try:
while True:
data = await websocket.receive_text()
await websocket.send_text(f"Message text was: {data}")
except WebSocketDisconnect:
print("Client disconnected")
if __name__ == "__main__":
import uvicorn
uvicorn.run(app, host="0.0.0.0", port=8000)
์ด๋ฅผ ์คํํ๋ ค๋ฉด `main.py`๋ก ์ ์ฅํ๊ณ `uvicorn main:app --reload`๋ฅผ ์คํํ์ญ์์ค.
์ด ์ฝ๋๋ฅผ ์์ธํ ์ดํด๋ณด๊ฒ ์ต๋๋ค.
@app.websocket("/ws"): ์ด ๋ฐ์ฝ๋ ์ดํฐ๋ ํจ์๋ฅผ/ws๊ฒฝ๋ก์ ๋ํ WebSocket ์๋ํฌ์ธํธ๋ก ๋ฑ๋กํฉ๋๋ค.async def websocket_endpoint(websocket: WebSocket):: FastAPI๋ ์๋์ผ๋กWebSocket๊ฐ์ฒด๋ฅผ ํจ์์ ์ฃผ์ ํ์ฌ ํต์ ๋ฐฉ๋ฒ์ ์ ๊ณตํฉ๋๋ค. WebSocket ์์ ์ ๋ณธ์ง์ ์ผ๋ก ๋น๋๊ธฐ์ ์ด๋ฏ๋ก ํจ์๋async์ฌ์ผ ํฉ๋๋ค.await websocket.accept(): ์ด๊ฒ์ด ์ค์ํฉ๋๋ค. ๋ค์ด์ค๋ WebSocket ์ฐ๊ฒฐ ์์ฒญ์ ์๋ฝํฉ๋๋ค. ์ด๊ฒ์ด ํธ์ถ๋ ๋๊น์ง ํธ๋์ ฐ์ดํฌ๊ฐ ์๋ฃ๋์ง ์์์ผ๋ฉฐ ๋ฉ์์ง๋ฅผ ๊ตํํ ์ ์์ต๋๋ค.while True:: ํด๋ผ์ด์ธํธ๋ก๋ถํฐ ๋ฉ์์ง๋ฅผ ์ง์์ ์ผ๋ก ์์ ํ๊ณ ์๋ตํ๊ธฐ ์ํ ๋ฃจํ์ ๋๋ค.data = await websocket.receive_text(): ํด๋ผ์ด์ธํธ๋ก๋ถํฐ ํ ์คํธ ๋ฉ์์ง๋ฅผ ์์ ํ ๋๊น์ง ๊ธฐ๋ค๋ฆฝ๋๋ค. ๋ค๋ฅธ ๋ฐ์ดํฐ ์ ํ์ ๋ํreceive_bytes()๋ฐreceive_json()๋ ์์ต๋๋ค.await websocket.send_text(f"Message text was: {data}"): ํด๋ผ์ด์ธํธ์ ํ ์คํธ ๋ฉ์์ง๋ฅผ ๋ค์ ๋ณด๋ ๋๋ค. ๋ง์ฐฌ๊ฐ์ง๋กsend_bytes()๋ฐsend_json()์ ์ฌ์ฉํ ์ ์์ต๋๋ค.except WebSocketDisconnect:: ํด๋ผ์ด์ธํธ๊ฐ ์ฐ๊ฒฐ์ ๋ซ์ ๋ ์ด ์์ธ๊ฐ ๋ฐ์ํฉ๋๋ค. ์ ๋ฆฌ ๋๋ ๋ก๊น ์ ์ํํ๋ ค๋ฉด ์ด๋ฅผ ์ก๋ ๊ฒ์ด ์ข์ต๋๋ค.
์ด๋ฅผ ํ ์คํธํ๊ธฐ ์ํด ๊ฐ๋จํ HTML/JavaScript ํด๋ผ์ด์ธํธ, Postman๊ณผ ๊ฐ์ ๋๊ตฌ ๋๋ Python WebSocket ํด๋ผ์ด์ธํธ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ฌ์ฉํ ์ ์์ต๋๋ค. ๋ค์์ ๊ฐ๋จํ HTML/JS ์์ ์ ๋๋ค.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>FastAPI WebSocket Echo</title>
</head>
<body>
<h1>WebSocket Echo Test</h1>
<input type="text" id="messageInput" placeholder="Type a message...">
<button onclick="sendMessage()">Send</button>
<div id="messages"></div>
<script>
const ws = new WebSocket("ws://localhost:8000/ws");
ws.onopen = (event) => {
document.getElementById('messages').innerHTML += '<p><b>Connected to WebSocket.</b></p>';
};
ws.onmessage = (event) => {
document.getElementById('messages').innerHTML += `<p>Received: ${event.data}</p>`;
};
ws.onclose = (event) => {
document.getElementById('messages').innerHTML += '<p><b>Disconnected.</b></p>';
};
ws.onerror = (error) => {
document.getElementById('messages').innerHTML += `<p style="color:red;">WebSocket Error: ${error.message}</p>`;
};
function sendMessage() {
const input = document.getElementById('messageInput');
const message = input.value;
if (message) {
ws.send(message);
document.getElementById('messages').innerHTML += `<p>Sent: ${message}</p>`;
input.value = '';
}
}
</script>
</body>
</html>
์ด HTML์ index.html๋ก ์ ์ฅํ๊ณ ๋ธ๋ผ์ฐ์ ์์ ์ด๋ฉด ๋ฉ์์ง๊ฐ ์ฆ์ ์์ฝ๋๋ ๊ฒ์ ๋ณผ ์ ์์ต๋๋ค.
FastAPI๋ก ๊ฐ๋จํ ์ค์๊ฐ ์ฑํ ์ ํ๋ฆฌ์ผ์ด์ ๊ตฌ์ถ
์์ฝ ์์ ๋ฅผ ํ์ฅํ์ฌ ๋ณด๋ค ๊ธฐ๋ฅ์ ์ด์ง๋ง ๊ฐ๋จํ ์ฑํ ์ ํ๋ฆฌ์ผ์ด์ ์ ๋ง๋ค์ด ๋ณด๊ฒ ์ต๋๋ค. ์ด๋ ๊ฒ ํ๋ฉด ์ฌ๋ฌ ํ์ฑ ์ฐ๊ฒฐ์ ๊ด๋ฆฌํ๊ณ ๋ชจ๋ ์ฐ๊ฒฐ๋ ํด๋ผ์ด์ธํธ์ ๋ฉ์์ง๋ฅผ ๋ธ๋ก๋์บ์คํธํ๋ ๋ฐฉ๋ฒ์ ๋ณด์ฌ์ค ์ ์์ต๋๋ค. ์ฐ๋ฆฌ๋ ์ ์ธ๊ณ ์ด๋์๋ ์ฌ์ฉ์๊ฐ ์ฐ๊ฒฐํ๊ณ ๋ํํ ์ ์๋ ๊ธ๋ก๋ฒ ์ฑํ ๋ฐฉ์ ์์ํ ๊ฒ์ ๋๋ค.
์๋ฒ ์ธก ๋ก์ง: ์ฐ๊ฒฐ ๊ด๋ฆฌ ๋ฐ ๋ธ๋ก๋์บ์คํ
์ฑํ ์ ํ๋ฆฌ์ผ์ด์ ์ ๊ฒฝ์ฐ ์๋ฒ๋ ๋ค์์ ์ํํด์ผ ํฉ๋๋ค.
- ๋ชจ๋ ํ์ฑ WebSocket ์ฐ๊ฒฐ์ ์ถ์ ํฉ๋๋ค.
- ์ ์ฐ๊ฒฐ์ ์๋ฝํฉ๋๋ค.
- ๋ชจ๋ ํด๋ผ์ด์ธํธ๋ก๋ถํฐ ๋ฉ์์ง๋ฅผ ์์ ํฉ๋๋ค.
- ์์ ๋ ๋ฉ์์ง๋ฅผ ๋ค๋ฅธ ๋ชจ๋ ์ฐ๊ฒฐ๋ ํด๋ผ์ด์ธํธ์ ๋ธ๋ก๋์บ์คํธํฉ๋๋ค.
- ํด๋ผ์ด์ธํธ ์ฐ๊ฒฐ ํด์ ๋ฅผ ์ ์์ ์ผ๋ก ์ฒ๋ฆฌํฉ๋๋ค.
๋ค์์ ๊ฐ๋จํ ์ฑํ ์๋ฒ๋ฅผ ์ํ FastAPI ๋ฐฑ์๋์ ๋๋ค.
from typing import List
from fastapi import FastAPI, WebSocket, WebSocketDisconnect
from pydantic import BaseModel
app = FastAPI()
class ConnectionManager:
def __init__(self):
self.active_connections: List[WebSocket] = []
async def connect(self, websocket: WebSocket):
await websocket.accept()
self.active_connections.append(websocket)
def disconnect(self, websocket: WebSocket):
self.active_connections.remove(websocket)
async def send_personal_message(self, message: str, websocket: WebSocket):
await websocket.send_text(message)
async def broadcast(self, message: str):
for connection in self.active_connections:
await connection.send_text(message)
manager = ConnectionManager()
@app.get("/")
async def get():
return {"message": "Hello, I'm a chat server! Go to /chat.html for the client."}
@app.websocket("/ws/{client_id}")
async def websocket_endpoint(websocket: WebSocket, client_id: int):
await manager.connect(websocket)
try:
while True:
data = await websocket.receive_text()
await manager.broadcast(f"Client #{client_id} says: {data}")
except WebSocketDisconnect:
manager.disconnect(websocket)
await manager.broadcast(f"Client #{client_id} left the chat.")
# --- Optional: Serving a static HTML client --- #
from fastapi.staticfiles import StaticFiles
app.mount("/", StaticFiles(directory="static", html=True), name="static")
์ฑํ ์๋ฒ ์ฝ๋๋ฅผ ์์ธํ ์ดํด๋ณด๊ฒ ์ต๋๋ค.
ConnectionManager: ์ด ํด๋์ค๋ ๋ชจ๋ ํ์ฑ WebSocket ์ฐ๊ฒฐ์ ๊ด๋ฆฌํ๋ ์ฑ ์์ด ์์ต๋๋ค. ๋ชฉ๋ก์ ์ ์ฅํฉ๋๋ค.connect(self, websocket): ์ฐ๊ฒฐ์ ์๋ฝํ ํ ์ ํด๋ผ์ด์ธํธ์ WebSocket์ ๋ชฉ๋ก์ ์ถ๊ฐํฉ๋๋ค.disconnect(self, websocket): ํด๋ผ์ด์ธํธ๊ฐ ์ฐ๊ฒฐ์ ๋์ผ๋ฉด ํด๋ผ์ด์ธํธ์ WebSocket์ ๋ชฉ๋ก์์ ์ ๊ฑฐํฉ๋๋ค.send_personal_message(): ํน์ ํด๋ผ์ด์ธํธ์ ๋ฉ์์ง๋ฅผ ๋ณด๋ด๊ธฐ ์ํ ๊ฒ์ ๋๋ค(์ด ๊ฐ๋จํ ๋ธ๋ก๋์บ์คํธ ์์ ์์๋ ์ฌ์ฉ๋์ง ์์ง๋ง ๊ฐ์ธ ๋ฉ์์ง์ ์ ์ฉํฉ๋๋ค).broadcast(self, message): ๋ชจ๋ ํ์ฑ ์ฐ๊ฒฐ์ ๋ฐ๋ณตํ๊ณ ๋์ผํ ๋ฉ์์ง๋ฅผ ๊ฐ ์ฐ๊ฒฐ์ ๋ณด๋ ๋๋ค.@app.websocket("/ws/{client_id}"): WebSocket ์๋ํฌ์ธํธ๋ ์ด์ client_id๊ฒฝ๋ก ๋งค๊ฐ๋ณ์๋ฅผ ๋ฐ์ต๋๋ค. ์ด๋ฅผ ํตํด ์ฑํ ์์ ๊ฐ๋ณ ํด๋ผ์ด์ธํธ๋ฅผ ์๋ณํ ์ ์์ต๋๋ค. ์ค์ ์๋๋ฆฌ์ค์์๋ ์ดclient_id๊ฐ ์ผ๋ฐ์ ์ผ๋ก ์ธ์ฆ ํ ํฐ ๋๋ ์ฌ์ฉ์ ์ธ์ ์์ ์ต๋๋ค.websocket_endpointํจ์ ๋ด์์ ํด๋ผ์ด์ธํธ๊ฐ ์ฐ๊ฒฐ๋ ํ ์๋ฒ๋ ๋ฃจํ์ ๋ค์ด๊ฐ๋๋ค. ์์ ๋ ๋ชจ๋ ๋ฉ์์ง๋ ๋ค๋ฅธ ๋ชจ๋ ํ์ฑ ์ฐ๊ฒฐ์ ๋ธ๋ก๋์บ์คํธ๋ฉ๋๋ค. ํด๋ผ์ด์ธํธ๊ฐ ์ฐ๊ฒฐ์ ๋์ผ๋ฉด ๋ชจ๋ ์ฌ๋์๊ฒ ์๋ฆฌ๊ธฐ ์ํด ๋ฉ์์ง๊ฐ ๋ธ๋ก๋์บ์คํธ๋ฉ๋๋ค.app.mount("/", StaticFiles(directory="static", html=True), name="static"): ์ด ์ค(์ ํ ์ฌํญ์ด์ง๋ง ์ ์ฉํจ)์static๋๋ ํ ๋ฆฌ์์ ์ ์ ํ์ผ์ ์ ๊ณตํฉ๋๋ค. HTML ํด๋ผ์ด์ธํธ๋ฅผ ๊ฑฐ๊ธฐ์ ๋ฃ์ ๊ฒ์ ๋๋ค.main.pyํ์ผ๊ณผ ๋์ผํ ์์น์ `static`์ด๋ผ๋ ๋๋ ํ ๋ฆฌ๋ฅผ ๋ง๋ค์ด์ผ ํฉ๋๋ค.
์ฑํ ์ ํ๋ฆฌ์ผ์ด์ ์ฉ ํด๋ผ์ด์ธํธ ์ธก HTML/JavaScript
static ๋๋ ํ ๋ฆฌ ์์ chat.html์ด๋ผ๋ ํ์ผ์ ๋ง๋ญ๋๋ค.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Global FastAPI Chat</title>
<style>
body { font-family: sans-serif; margin: 20px; background-color: #f4f4f4; }
#chat-container { max-width: 600px; margin: auto; background: white; padding: 20px; border-radius: 8px; box-shadow: 0 2px 4px rgba(0,0,0,0.1); }
#messages { border: 1px solid #ddd; height: 300px; overflow-y: scroll; padding: 10px; margin-bottom: 10px; background-color: #e9e9e9; }
#messageInput { width: calc(100% - 80px); padding: 8px; border: 1px solid #ddd; border-radius: 4px; }
#sendButton { width: 70px; padding: 8px; background-color: #007bff; color: white; border: none; border-radius: 4px; cursor: pointer; }
#sendButton:hover { background-color: #0056b3; }
.message-entry { margin-bottom: 5px; }
.system-message { color: grey; font-style: italic; }
</style>
</head>
<body>
<div id="chat-container">
<h1>Global Chat Room</h1>
<p>Enter your client ID to join the chat.</p>
<input type="number" id="clientIdInput" placeholder="Client ID (e.g., 123)" value="1">
<button onclick="connectWebSocket()" id="connectButton">Connect</button>
<button onclick="disconnectWebSocket()" id="disconnectButton" disabled>Disconnect</button>
<hr>
<div id="messages"></div>
<input type="text" id="messageInput" placeholder="Type your message..." disabled>
<button onclick="sendMessage()" id="sendButton" disabled>Send</button>
</div>
<script>
let ws = null;
let clientId = null;
const messagesDiv = document.getElementById('messages');
const clientIdInput = document.getElementById('clientIdInput');
const messageInput = document.getElementById('messageInput');
const connectButton = document.getElementById('connectButton');
const disconnectButton = document.getElementById('disconnectButton');
const sendButton = document.getElementById('sendButton');
function logMessage(message, isSystem = false) {
const p = document.createElement('p');
p.textContent = message;
if (isSystem) {
p.classList.add('system-message');
} else {
p.classList.add('message-entry');
}
messagesDiv.appendChild(p);
messagesDiv.scrollTop = messagesDiv.scrollHeight; // Auto-scroll to bottom
}
function enableChatControls(enable) {
messageInput.disabled = !enable;
sendButton.disabled = !enable;
clientIdInput.disabled = enable;
connectButton.disabled = enable;
disconnectButton.disabled = !enable;
}
function connectWebSocket() {
clientId = clientIdInput.value;
if (!clientId) {
alert('Please enter a Client ID.');
return;
}
logMessage(`Attempting to connect as Client #${clientId}...`, true);
ws = new WebSocket(`ws://localhost:8000/ws/${clientId}`);
ws.onopen = (event) => {
logMessage(`Connected to chat as Client #${clientId}.`, true);
enableChatControls(true);
};
ws.onmessage = (event) => {
logMessage(event.data);
};
ws.onclose = (event) => {
logMessage('Disconnected from chat.', true);
ws = null;
enableChatControls(false);
};
ws.onerror = (error) => {
logMessage(`WebSocket Error: ${error.message}`, true);
logMessage('Please check server status and try again.', true);
ws = null;
enableChatControls(false);
};
}
function disconnectWebSocket() {
if (ws) {
ws.close();
}
}
function sendMessage() {
const message = messageInput.value;
if (message && ws && ws.readyState === WebSocket.OPEN) {
ws.send(message);
messageInput.value = ''; // Clear input after sending
}
}
// Allow sending message by pressing Enter key
messageInput.addEventListener('keypress', function(e) {
if (e.key === 'Enter') {
sendMessage();
}
});
// Initial state
enableChatControls(false);
</script>
</body>
</html>
์ด์ FastAPI ์๋ฒ๋ฅผ ์คํํ๊ณ ์ฌ๋ฌ ๋ธ๋ผ์ฐ์ ํญ ๋๋ ๋ค๋ฅธ ๋ธ๋ผ์ฐ์ ์์ http://localhost:8000/chat.html์ ์ฝ๋๋ค. ๊ฐ ํญ์ ๊ณ ์ ํ ํด๋ผ์ด์ธํธ ID(์: 1, 2, 3)๋ฅผ ํ ๋นํ๊ณ ์ฐ๊ฒฐํฉ๋๋ค. ํ ํญ์ ์
๋ ฅํ ๋ฉ์์ง๊ฐ ๋ค๋ฅธ ๋ชจ๋ ํญ์ ์ฆ์ ๋ํ๋๋ ๊ฒ์ ๋ณผ ์ ์์ผ๋ฉฐ, ์ด๋ ์ค์๊ฐ ๊ธ๋ก๋ฒ ์ฑํ
ํ๊ฒฝ์ ์๋ฎฌ๋ ์ด์
ํฉ๋๋ค!
์ด ๊ฐ๋จํ ์ฑํ ์ ํ๋ฆฌ์ผ์ด์ ์ ํต์ฌ ์์น์ ์์ฐํฉ๋๋ค. ํ๋ก๋์ ์ค๋น ์ ํ๋ฆฌ์ผ์ด์ ์ ๊ฒฝ์ฐ ์ฌ์ฉ์ ์ธ์ฆ, ์ง์์ ์ธ ๋ฉ์์ง ์ ์ฅ, ์ฌ๋ฌ ์ฑํ ๋ฐฉ ์ง์ ๋ฐ ๋ ๊ฐ๋ ฅํ ์ค๋ฅ ์ฒ๋ฆฌ๋ฅผ ์ถ๊ฐํด์ผ ํฉ๋๋ค.
๊ณ ๊ธ WebSocket ํจํด ๋ฐ ๊ธ๋ก๋ฒ ๋ฐฐํฌ ๊ณ ๋ ค ์ฌํญ
๊ธ๋ก๋ฒ ์ค์๊ฐ ์ ํ๋ฆฌ์ผ์ด์ ์ ํ์ฅํ๋ ๊ฒ์ ๊ธฐ๋ณธ WebSocket ํธ๋ค๋ฌ ์์ฑ ์ด์์ ๊ฒ์ ํฌํจํฉ๋๋ค. ๊ณ ๋ คํด์ผ ํ ์ค์ํ ์ธก๋ฉด์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
1. ์ฐ๊ฒฐ ๊ด๋ฆฌ ๋ฐ ์ํ
- ๊ธ๋ก๋ฒ ์ฐ๊ฒฐ ์ํ: ๊ฐ๋จํ ์ฑํ
์์
ConnectionManager๋ ์ฐ๊ฒฐ์ ๋ฉ๋ชจ๋ฆฌ์ ์ ์ฅํฉ๋๋ค. ๋จ์ผ ์๋ฒ ์ธ์คํด์ค์ ๊ฒฝ์ฐ ๊ด์ฐฎ์ต๋๋ค. ์ฌ๋ฌ ์๋ฒ ์ธ์คํด์ค(์: ๋ค๋ฅธ ์ง๋ฆฌ์ ์ง์ญ์ ๊ฑธ์ณ)์ ๊ฒฝ์ฐ ๊ณต์ ์ํ ๋ฉ์ปค๋์ฆ์ด ํ์ํฉ๋๋ค. - Redis Pub/Sub: ์ผ๋ฐ์ ์ธ ํจํด์ Redis์ ๊ฒ์/๊ตฌ๋ (Pub/Sub) ๊ธฐ๋ฅ์ ์ฌ์ฉํ๋ ๊ฒ์ ๋๋ค. ํ FastAPI ์ธ์คํด์ค๊ฐ ๋ฉ์์ง๋ฅผ ์์ ํ๋ฉด Redis ์ฑ๋์ ๋ฉ์์ง๋ฅผ ๊ฒ์ํฉ๋๋ค. ํด๋น ์ฑ๋์ ๊ตฌ๋ ํ๋ ๋ค๋ฅธ ๋ชจ๋ FastAPI ์ธ์คํด์ค(๋ค๋ฅธ ๋ฐ์ดํฐ ์ผํฐ์ ๊ฑธ์ณ ์์ ์ ์์)๋ ๋ฉ์์ง๋ฅผ ์์ ํ๊ณ ๋ก์ปฌ WebSocket ํด๋ผ์ด์ธํธ์ ๋ธ๋ก๋์บ์คํธํฉ๋๋ค. ์ด๋ฅผ ํตํด ์ํ ํ์ฅ์ด ๊ฐ๋ฅํฉ๋๋ค.
- ํํธ๋นํธ(Ping/Pong): WebSockets๋ ๋คํธ์ํฌ ๋ฌธ์ ๋๋ ํ๋ก์ ์๊ฐ ์ด๊ณผ๋ก ์ธํด ์ฐ๊ฒฐ์ด ์กฐ์ฉํ ๋์ด์ง ์ ์์ต๋๋ค. Ping/Pong ํํธ๋นํธ ๋ฉ์ปค๋์ฆ(์๋ฒ๊ฐ ์ฃผ๊ธฐ์ ์ผ๋ก "ping" ํ๋ ์์ ๋ณด๋ด๊ณ "pong" ์๋ต์ ๊ธฐ๋ํ๋)์ ๊ตฌํํ๋ฉด ์ค๋๋ ์ฐ๊ฒฐ์ ๊ฐ์งํ๊ณ ๋ซ์ ์๋ฒ ๋ฆฌ์์ค๋ฅผ ํ๋ณดํ๋ ๋ฐ ๋์์ด ๋ฉ๋๋ค.
2. ์ธ์ฆ ๋ฐ ๊ถํ ๋ถ์ฌ
ํนํ ์ ์ธ๊ณ์ ์ผ๋ก ๋ฏผ๊ฐํ ์ฌ์ฉ์ ๋ฐ์ดํฐ๋ฅผ ์ฒ๋ฆฌํ ๋ WebSocket ์ฐ๊ฒฐ์ ๋ณด์ํ๋ ๊ฒ์ด ๊ฐ์ฅ ์ค์ํฉ๋๋ค.
- ์ด๊ธฐ ํธ๋์
ฐ์ดํฌ ์ธ์ฆ: ๊ฐ์ฅ ์ผ๋ฐ์ ์ธ ์ ๊ทผ ๋ฐฉ์์ ์ฐ๊ฒฐ์ด WebSocket์ผ๋ก ์
๊ทธ๋ ์ด๋๋๊ธฐ ์ ์ ์ด๊ธฐ HTTP ํธ๋์
ฐ์ดํฌ ๋จ๊ณ์์ ์ฌ์ฉ์๋ฅผ ์ธ์ฆํ๋ ๊ฒ์
๋๋ค. ์ด๋ WebSocket URL์ ์ฟผ๋ฆฌ ๋งค๊ฐ๋ณ์(
ws://example.com/ws?token=your_jwt) ๋๋ ํด๋ผ์ด์ธํธ๊ฐ ํ์ฉํ๋ ๊ฒฝ์ฐ HTTP ํค๋์ ์ธ์ฆ ํ ํฐ(์: JWT)์ ๋ณด๋ด์ ์ํํ ์ ์์ต๋๋ค. ๊ทธ๋ฐ ๋ค์ FastAPI๋await websocket.accept()๋ฅผ ํธ์ถํ๊ธฐ ์ ์ ์ด ํ ํฐ์ ๊ฒ์ฆํ ์ ์์ต๋๋ค. - ๊ถํ ๋ถ์ฌ ๋ฏธ๋ค์จ์ด: ๋ ๋ณต์กํ ์๋๋ฆฌ์ค์ ๊ฒฝ์ฐ WebSocket ์ฐ๊ฒฐ์ ๊ฐ๋ก์ฑ๊ณ ๊ถํ ๋ถ์ฌ ๊ฒ์ฌ๋ฅผ ์ํํ๋ฉฐ ์ฌ์ฉ์ ์ปจํ ์คํธ๋ฅผ WebSocket ๋ฒ์์ ์ฃผ์ ํ๋ ASGI ๋ฏธ๋ค์จ์ด๋ฅผ ๊ตฌํํ ์ ์์ต๋๋ค.
3. ์ค๋ฅ ์ฒ๋ฆฌ ๋ฐ ๋ก๊น
์์ ์ ์ธ ๊ธ๋ก๋ฒ ์ ํ๋ฆฌ์ผ์ด์ ์ ๊ฒฝ์ฐ ํด๋ผ์ด์ธํธ์ ์๋ฒ ๋ชจ๋์ ๊ฐ๋ ฅํ ์ค๋ฅ ์ฒ๋ฆฌ๊ฐ ์ค์ํฉ๋๋ค.
- ์๋ฒ ์ธก: WebSocket ์์
์ฃผ์์ ์ ์ ํ
try...except๋ธ๋ก์ ๊ตฌํํฉ๋๋ค. ์์ธํ ์ ๋ณด(์: ํด๋ผ์ด์ธํธ ID, ์ค๋ฅ ๋ฉ์์ง, ํ์์คํฌํ, ์๋ฒ์ ์ง๋ฆฌ์ ์์ญ)๋ฅผ ์ฌ์ฉํ์ฌ ๊ตฌ์กฐํ๋ ๋ก๊น ์๋ฃจ์ ์ผ๋ก ์ค๋ฅ๋ฅผ ๊ธฐ๋กํฉ๋๋ค. - ํด๋ผ์ด์ธํธ ์ธก: ํด๋ผ์ด์ธํธ๋ ์ฐ๊ฒฐ ์ค๋ฅ, ๋คํธ์ํฌ ์ค๋จ ๋ฐ ์๋ฒ์์ ๋ณด๋ธ ์ค๋ฅ ๋ฉ์์ง๋ฅผ ์ ์์ ์ผ๋ก ์ฒ๋ฆฌํด์ผ ํฉ๋๋ค. ์๋ฒ์ ๊ณผ๋ถํ๊ฐ ๊ฑธ๋ฆฌ๋ ๊ฒ์ ํผํ๊ธฐ ์ํด ์ง์ ๋ฐฑ์คํ๋ฅผ ์ฌ์ฉํ์ฌ ์ฌ์ฐ๊ฒฐ์ ์ํ ์ฌ์๋ ๋ฉ์ปค๋์ฆ์ ๊ตฌํํฉ๋๋ค.
4. ๋ฐ์ดํฐ ํ์ ๋ฐ ์คํค๋ง ์ ํจ์ฑ ๊ฒ์ฌ
ํ ์คํธ ๋ฉ์์ง(๋ฌธ์์ด)๊ฐ ์ผ๋ฐ์ ์ด์ง๋ง ๊ตฌ์กฐํ๋ ๋ฐ์ดํฐ์ ๊ฒฝ์ฐ JSON์ด ๋๋ฆฌ ์ฌ์ฉ๋ฉ๋๋ค. FastAPI์ Pydantic ๋ชจ๋ธ์ ์ฌ๊ธฐ์ ๋งค์ฐ ์ ์ฉํ ์ ์์ต๋๋ค.
from pydantic import BaseModel
class ChatMessage(BaseModel):
sender_id: int
message: str
timestamp: float # UTC timestamp
room_id: str
@app.websocket("/ws/{client_id}")
async def websocket_endpoint(websocket: WebSocket, client_id: int):
await manager.connect(websocket)
try:
while True:
json_data = await websocket.receive_json()
chat_message = ChatMessage(**json_data) # Validate incoming JSON
# Process message, then send JSON back
await manager.broadcast_json(chat_message.dict())
except WebSocketDisconnect:
manager.disconnect(websocket)
# Broadcast client leaving
Pydantic์ ์ฌ์ฉํ๋ฉด WebSocket์ ํตํด ๊ตํ๋๋ ๋ฐ์ดํฐ๊ฐ ๋ฏธ๋ฆฌ ์ ์๋ ์คํค๋ง๋ฅผ ์ค์ํ๋์ง ํ์ธํ์ฌ ์๋ชป๋ ํ์์ ๋ฉ์์ง๊ฐ ์ ํ๋ฆฌ์ผ์ด์ ์ ์ถฉ๋์ํค๋ ๊ฒ์ ๋ฐฉ์งํ๊ณ ๋ค๋ฅธ ์ง์ญ ๋ฐ ํ ๊ฐ์ ์์ ํ๋ ๊ฐ๋ฐ์๋ฅผ ์ํ ๋ช ํํ ๋ฐ์ดํฐ ๊ณ์ฝ์ ์ ๊ณตํฉ๋๋ค.
5. ๋ฐฐํฌ ๋ฐ ํ์ฅ ์ ๋ต
๊ธ๋ก๋ฒ ๋๋ฌ ๋ฒ์๋ฅผ ์ํด์๋ ํ์ฅ์ฑ์ด ๊ฐ์ฅ ์ค์ํฉ๋๋ค. FastAPI WebSocket ์ ํ๋ฆฌ์ผ์ด์ ์ ๋ค์ํ ์ง์ญ์ ๋ค์ํ ๋ถํ๋ฅผ ์ฒ๋ฆฌํด์ผ ํฉ๋๋ค.
- Uvicorn ์์ปค: ์ฌ๋ฌ ์์ปค ํ๋ก์ธ์ค(์:
uvicorn main:app --workers 4)๋ก Uvicorn์ ์คํํ์ฌ ๋ฉํฐ์ฝ์ด CPU๋ฅผ ํ์ฉํฉ๋๋ค. - ๋ฆฌ๋ฒ์ค ํ๋ก์(Nginx, Traefik): FastAPI ์ ํ๋ฆฌ์ผ์ด์ ์์ ๋ฆฌ๋ฒ์ค ํ๋ก์๋ฅผ ๋ฐฐ์นํฉ๋๋ค. ์ด๋ฌํ ํ๋ก์๋ SSL/TLS ์ข ๋ฃ, ๋ก๋ ๋ฐธ๋ฐ์ฑ ๋ฐ WebSocket์ผ๋ก์ ์ฐ๊ฒฐ ์ ๊ทธ๋ ์ด๋๋ฅผ ์ฒ๋ฆฌํ ์ ์์ต๋๋ค. ๋ํ ๋์ ์ฐ๊ฒฐ์ ๋ณด๋ค ํจ์จ์ ์ผ๋ก ๊ด๋ฆฌํ๋ ๋ฐ ๋์์ด ๋ฉ๋๋ค.
- ๊ณ ์ ์ธ์ ์ด ์๋ ๋ก๋ ๋ฐธ๋ฐ์: ์ฌ๋ฌ ๋ฐฑ์๋ ์ธ์คํด์ค๋ฅผ ๋ฐฐํฌํ ๋ ํ์ค ๋ผ์ด๋ ๋ก๋น ๋ก๋ ๋ฐธ๋ฐ์๋ ๋์ผํ ํด๋ผ์ด์ธํธ์ ํ์ WebSocket ๋ฉ์์ง๋ฅผ ๋ค๋ฅธ ์๋ฒ๋ก ๋ผ์ฐํ ํ์ฌ ์ฐ๊ฒฐ์ ๋์ ์ ์์ต๋๋ค. "๊ณ ์ ์ธ์ "(๋๋ "์ธ์ ์ ํธ๋")์ผ๋ก ๊ตฌ์ฑ๋ ๋ก๋ ๋ฐธ๋ฐ์๊ฐ ํ์ํ๋ฉฐ, ์ด๋ ํด๋ผ์ด์ธํธ์ WebSocket ์ฐ๊ฒฐ์ด ํญ์ ๋์ผํ ๋ฐฑ์๋ ์๋ฒ๋ก ๋ผ์ฐํ ๋๋๋ก ๋ณด์ฅํฉ๋๋ค. ๊ทธ๋ฌ๋ ์ด๋ ์ํ ํ์ฅ์ ๋ณต์กํ๊ฒ ๋ง๋ญ๋๋ค.
- ๋ถ์ฐ ๋ฉ์์ง ์์คํ (Redis, Kafka): ์ธ๊ธํ ๋ฐ์ ๊ฐ์ด ์ง์ ์ผ๋ก ํ์ฅ ๊ฐ๋ฅํ๊ณ ๋ถ์ฐ๋ WebSocket ์ ํ๋ฆฌ์ผ์ด์ ์ ๊ฒฝ์ฐ ๋ฐฑ์๋ ๋ฉ์์ง ํ(Redis Pub/Sub, Apache Kafka ๋๋ RabbitMQ ๋ฑ)๊ฐ ํ์์ ์ ๋๋ค. ๊ฐ FastAPI ์ธ์คํด์ค๋ ๊ฒ์์ ๋ฐ ๊ตฌ๋ ์๋ก ์๋ํ์ฌ ํด๋ผ์ด์ธํธ๊ฐ ์ฐ๊ฒฐ๋ ์๋ฒ์ ๊ด๊ณ์์ด ๋ฉ์์ง๊ฐ ๋ชจ๋ ๊ด๋ จ ํด๋ผ์ด์ธํธ์ ์ ๋ฌ๋๋๋ก ํฉ๋๋ค.
- ์ง๋ฆฌ์ ๋ฐฐํฌ(CDN, ์ฃ์ง ์ปดํจํ ): WebSocket ์๋ฒ๋ฅผ ์ฃผ์ ์ฌ์ฉ์ ๊ธฐ๋ฐ์ ๋ ๊ฐ๊น์ด ๋ฐ์ดํฐ ์ผํฐ์ ๋ฐฐํฌํ๋ฉด(์: ์ ๋ฝ, ์์์, ๋ถ๋ฏธ์ ํ๋์ฉ) ์ง์ฐ ์๊ฐ์ ํฌ๊ฒ ์ค์ผ ์ ์์ต๋๋ค. Cloudflare์ WebSockets ๋๋ AWS API Gateway์ WebSockets์ ๊ฐ์ ์๋น์ค๋ ๊ธ๋ก๋ฒ ๋ฐฐํฌ๋ฅผ ๊ด๋ฆฌํ๋ ๋ฐ ๋์์ด ๋ฉ๋๋ค.
6. WebSocket์ฉ ๊ต์ฐจ ์ถ์ฒ ๋ฆฌ์์ค ๊ณต์ (CORS)
WebSocket ํด๋ผ์ด์ธํธ(์: ์น ๋ธ๋ผ์ฐ์ )๊ฐ FastAPI WebSocket ์๋ฒ์ ๋ค๋ฅธ ๋๋ฉ์ธ์์ ์ ๊ณต๋๋ ๊ฒฝ์ฐ ์ด๊ธฐ HTTP ํธ๋์
ฐ์ดํฌ ์ค์ CORS ๋ฌธ์ ๊ฐ ๋ฐ์ํ ์ ์์ต๋๋ค. Starlette(๋ฐ๋ผ์ FastAPI)๋ ์ด๋ฅผ ์ฒ๋ฆฌํ๊ธฐ ์ํด CORSMiddleware๋ฅผ ์ ๊ณตํฉ๋๋ค.
from fastapi import FastAPI, WebSocket, WebSocketDisconnect
from fastapi.middleware.cors import CORSMiddleware
app = FastAPI()
origins = [
"http://localhost:3000", # Your client application's origin
"http://your-global-app.com",
# Add other origins as needed
]
app.add_middleware(
CORSMiddleware,
allow_origins=origins,
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
# ... your WebSocket endpoint code ...
allow_origins๋ฅผ ์ ๋ขฐํ๋ ๋๋ฉ์ธ๋ง ํฌํจํ๋๋ก ์ ์คํ๊ฒ ๊ตฌ์ฑํ์ฌ ๋ณด์ ์ทจ์ฝ์ ์ ๋ฐฉ์งํ์ญ์์ค.
FastAPI WebSocket์ ์ค์ ๊ธ๋ก๋ฒ ์ ํ๋ฆฌ์ผ์ด์
์ผ๋ถ ๊ธ๋ก๋ฒ ์ ํ๋ฆฌ์ผ์ด์ ์ ๋ค์ ์ดํด๋ณด๊ณ FastAPI์ WebSocket ์ง์์ด ์ด๋ป๊ฒ ์ด๋ฅผ ์ง์ํ๋์ง ์ดํด๋ณด๊ฒ ์ต๋๋ค.
- ๋ผ์ด๋ธ ์ฃผ์ ์์ฅ ๋ฐ ์ํธํํ ๋์๋ณด๋: ์๋๋, ํ๋ํฌํธ๋ฅดํธ, ๋ด์์ ํฌ์์๋ค์ด ์ฌ์ฉํ๋ ๊ฑฐ๋ ํ๋ซํผ์ ์์ํด ๋ณด์ญ์์ค. FastAPI๋ ๋ค์ํ ๊ฑฐ๋์์์ ์ค์๊ฐ ๊ฐ๊ฒฉ ํผ๋๋ฅผ ์์ ํ๊ณ ์ฐ๊ฒฐ๋ ๋ชจ๋ ํด๋ผ์ด์ธํธ์ WebSocket์ ํตํด ์ ๋ฐ์ดํธ๋ฅผ ํธ์ํ์ฌ ๋ชจ๋ ์ฌ๋์ด ์์ ์ ์์น์ ๊ด๊ณ์์ด ์ต์ ์์ฅ ๋ฐ์ดํฐ๋ฅผ ๋์์ ๋ณผ ์ ์๋๋ก ํ ์ ์์ต๋๋ค.
- ํ์ ํ์ดํธ๋ณด๋ ๋ฐ ํ๋ก์ ํธ ๊ด๋ฆฌ ๋๊ตฌ: ๊ณต์ ์๊ฐ ๋ณด๋์์ ์์ ํ๊ฑฐ๋ ํ๋ก์ ํธ ์งํ ์ํฉ์ ์ถ์ ํ๋ ๋ถ์ฐ ํ์ ์ฆ๊ฐ์ ์ธ ์ ๋ฐ์ดํธ๊ฐ ํ์ํฉ๋๋ค. FastAPI WebSockets๋ ๋ค๋ฅธ ๋ชจ๋ ํ์ ์์๊ฒ ๊ทธ๋ฆฌ๊ธฐ ํ ๋๋ ์์ ์ํ ๋ณ๊ฒฝ ์ฌํญ์ด ๋ธ๋ก๋์บ์คํธ๋๋ ๊ธฐ๋ฅ์ ์ง์ํ์ฌ ์๊ฐ๋์ ๊ฑธ์ณ ์์ฐ์ฑ์ ํฅ์์ํฌ ์ ์์ต๋๋ค.
- ๋ฉํฐํ๋ ์ด์ด ๊ฒ์ ๋ฐฑ์๋(๋ ๊ฐ๋ฒผ์ด ๊ฒ์): ๋ธ๋ผ์ฐ์ ๊ธฐ๋ฐ ์บ์ฃผ์ผ ๊ฒ์ ๋๋ ํด ๊ธฐ๋ฐ ์ ๋ต ๊ฒ์์ ๊ฒฝ์ฐ FastAPI๋ ๊ฒ์ ์ํ, ํ๋ ์ด์ด ์ด๋ ๋ฐ ์ ์ธ๊ณ ํ๋ ์ด์ด ๊ฐ์ ์ฑํ ์ ๊ด๋ฆฌํ ์ ์์ต๋๋ค. AAA ํ์ดํ์ ๊ฒฝ์ฐ ๋ ์ ๋ฌธ์ ์ธ ๊ฒ์ ์๋ฒ๋ฅผ ์ ํํ ์ ์์ง๋ง FastAPI๋ ๋ง์ ๋ํํ ์น ๊ฒ์์ ์๋ฒฝํ๊ฒ ์ ํฉํฉ๋๋ค.
- ๊ธ๋ก๋ฒ IoT ๋ชจ๋ํฐ๋ง ์์คํ : ๋ ์ผ, ๋ธ๋ผ์ง, ์ผ๋ณธ์ ๊ณต์ฅ ์ผ์๋ฅผ ๋ชจ๋ํฐ๋งํ๋ ํ์ฌ๋ FastAPI๋ฅผ ์ค์ WebSocket ์๋ฒ๋ก ์ฌ์ฉํ ์ ์์ต๋๋ค. ์ผ์ ๋ฐ์ดํฐ๋ FastAPI๋ก ์คํธ๋ฆฌ๋ฐ๋๊ณ , FastAPI๋ ์ ์ธ๊ณ ์ด์ ํ์ด ๋ณด๋ ๋์๋ณด๋๋ก ์ค์ํ ๊ฒฝ๊ณ ๋๋ ์ํ ์ ๋ฐ์ดํธ๋ฅผ ํธ์ํฉ๋๋ค.
- ์ฆ๊ฐ์ ์ธ ์๋ฆผ ์๋น์ค: ์๋ณด ์๋ฆผ๋ถํฐ ์์ ๋ฏธ๋์ด ์๋ฆผ๊น์ง FastAPI๋ ๊ฐ์ธํ๋ ์๋ฆผ์ ์ ์ธ๊ณ ์๋ฐฑ๋ง ์ฌ์ฉ์์๊ฒ ํจ์จ์ ์ผ๋ก ํธ์ํ ์ ์์ต๋๋ค. ๋ค๋ฅธ ์ง์ญ์ ์ฌ์ฉ์๋ค์ ๊ฑฐ์ ๋์์ ์๋ฆผ์ ๋ฐ์ ์ฐธ์ฌ๋ฅผ ํฅ์์ํต๋๋ค.
- ์๊ฒฉ ๊ต์ก ๋ฐ ๊ฐ์ ์ด๋ฒคํธ ํ๋ซํผ: ๋ผ์ด๋ธ ์จ๋ผ์ธ ๊ฐ์ ๋๋ ์ปจํผ๋ฐ์ค ์ค์ FastAPI๋ ์ค์๊ฐ Q&A ์ธ์ , ์ค๋ฌธ ์กฐ์ฌ ๋ฐ ๋ํํ ์์๋ฅผ ์ด์งํ์ฌ ๋ค์ํ ๊ต์ก ๋ฐฐ๊ฒฝ๊ณผ ๊ตญ๊ฐ์ ์ฐธ๊ฐ์๊ฐ ์ํํ๊ฒ ์ฐธ์ฌํ ์ ์๋๋ก ํฉ๋๋ค.
FastAPI WebSockets๋ฅผ ์ฌ์ฉํ ๊ธ๋ก๋ฒ ๋ฐฐํฌ ๋ชจ๋ฒ ์ฌ๋ก
์ง์ ํ ์ธ๊ณ์ ์์ค์ ์ค์๊ฐ ์ ํ๋ฆฌ์ผ์ด์ ์ ๊ตฌ์ถํ๋ ค๋ฉด ์ด๋ฌํ ๊ธ๋ก๋ฒ ๋ชจ๋ฒ ์ฌ๋ก๋ฅผ ๊ณ ๋ คํ์ญ์์ค.
- ๋ฎ์ ์ง์ฐ ์๊ฐ ์ํคํ
์ฒ:
- ์ ์ ์์ฐ์ฉ CDN: ์ ์ธ๊ณ ํด๋ผ์ด์ธํธ์ ๋น ๋ฅธ ๋ก๋ฉ ์๊ฐ์ ๋ณด์ฅํ๊ธฐ ์ํด CDN(์ฝํ ์ธ ์ ์ก ๋คํธ์ํฌ)์์ HTML, CSS, JavaScript๋ฅผ ์ ๊ณตํฉ๋๋ค.
- ์ง๋ฆฌ์ ์ผ๋ก ๋ถ์ฐ๋ ์๋ฒ: FastAPI WebSocket ์๋ฒ๋ฅผ ์ฌ์ฉ์ ๊ธฐ๋ฐ์ ๊ฐ๊น์ด ์ฌ๋ฌ ์ง๋ฆฌ์ ์์ญ์ ๋ฐฐํฌํฉ๋๋ค. DNS ๋ผ์ฐํ (AWS Route 53 ๋๋ Google Cloud DNS์ ๊ฐ์)์ ์ฌ์ฉํ์ฌ ์ฌ์ฉ์์๊ฒ ๊ฐ์ฅ ๊ฐ๊น์ด ์๋ฒ๋ก ์๋ดํฉ๋๋ค.
- ์ต์ ํ๋ ๋คํธ์ํฌ ๊ฒฝ๋ก: ์ง์ญ ๊ฐ ์ต์ ํ๋ ๋ผ์ฐํ ์ ์ ๊ณตํ๋ ํด๋ผ์ฐ๋ ๊ณต๊ธ์ ๋คํธ์ํฌ ์๋น์ค๋ฅผ ๊ณ ๋ คํ์ญ์์ค.
- ํ์ฅ์ฑ ๋ฐ ๋ณต์๋ ฅ:
- ์ํ ํ์ฅ: ์๋ฒ ์ธ์คํด์ค๋ฅผ ๋ ์ถ๊ฐํ์ฌ ์ํ์ผ๋ก ํ์ฅํ ์ ์๋๋ก ์ ํ๋ฆฌ์ผ์ด์ ์ ์ค๊ณํฉ๋๋ค. ์๋ฒ ๊ฐ ํต์ ์ ์ํด ๋ถ์ฐ ๋ฉ์์ง ๋ธ๋ก์ปค(Redis Pub/Sub, Kafka)๋ฅผ ์ฌ์ฉํฉ๋๋ค.
- ์ํ ๋น์ ์ฅ WebSocket ํธ๋ค๋ฌ: ๊ฐ๋ฅํ ๊ฒฝ์ฐ WebSocket ํธ๋ค๋ฌ๋ฅผ ์ํ ๋น์ ์ฅ์ผ๋ก ์ ์งํ๊ณ ์ํ ๊ด๋ฆฌ๋ฅผ ๋ณ๋์ ํ์ฅ ๊ฐ๋ฅํ ์๋น์ค(๋ถ์ฐ ์บ์ ๋๋ ๋ฐ์ดํฐ๋ฒ ์ด์ค ๋ฑ)๋ก ํธ์ํฉ๋๋ค.
- ๊ณ ๊ฐ์ฉ์ฑ: ๊ฐ์ฉ์ฑ ์์ญ ๋๋ ์ง์ญ์ ๊ฑธ์ณ ์ค๋ณต ์๋ฒ, ๋ฐ์ดํฐ๋ฒ ์ด์ค ๋ฐ ๋ฉ์์ง ๋ธ๋ก์ปค๋ฅผ ์ฌ์ฉํ์ฌ ์ธํ๋ผ๊ฐ ๋ด๊ฒฐํจ์ฑ์ธ์ง ํ์ธํฉ๋๋ค.
- ๊ตญ์ ํ(i18n) ๋ฐ ํ์งํ(l10n):
- ํด๋ผ์ด์ธํธ ์ธก ํ์งํ: ์ฑํ ๋ฉ์์ง ๋๋ ์ฌ์ฉ์์๊ฒ ํ์๋๋ UI ์์์ ๊ฒฝ์ฐ ์ฌ์ฉ์์ ๋ธ๋ผ์ฐ์ ์ธ์ด ์ค์ ์ ๊ธฐ๋ฐ์ผ๋ก ํด๋ผ์ด์ธํธ ์ธก์์ ํ์งํ๋ฅผ ์ฒ๋ฆฌํฉ๋๋ค.
- UTF-8 ์ธ์ฝ๋ฉ: WebSocket์ ํตํด ๊ตํ๋๋ ๋ชจ๋ ๋ฐ์ดํฐ๊ฐ UTF-8 ์ธ์ฝ๋ฉ์ ์ฌ์ฉํ๋๋ก ํ์ฌ ์ ์ธ๊ณ ๋ค์ํ ์ธ์ด์ ๋ค์ํ ๋ฌธ์ ์ธํธ๋ฅผ ์ง์ํฉ๋๋ค. Python๊ณผ FastAPI๋ ์ด๋ฅผ ๊ธฐ๋ณธ์ ์ผ๋ก ์ฒ๋ฆฌํฉ๋๋ค.
- ์๊ฐ๋ ์ธ์: ๋ชจ๋ ํ์์คํฌํ๋ฅผ ์๋ฒ์ UTC๋ก ์ ์ฅํ๊ณ ํ์๋ฅผ ์ํด ์ฌ์ฉ์ ํ์ง ์๊ฐ๋๋ก ํด๋ผ์ด์ธํธ ์ธก์์ ๋ณํํฉ๋๋ค.
- ๋ณด์ ๋ฐ ๊ท์ ์ค์:
- ํญ์ WSS(TLS/SSL) ์ฌ์ฉ: ์ ์ก ์ค์ธ ๋ฐ์ดํฐ๋ฅผ ๋ณดํธํ๊ธฐ ์ํด
wss://(WebSocket Secure)๋ฅผ ์ฌ์ฉํ์ฌ ๋ชจ๋ WebSocket ํธ๋ํฝ์ ์ํธํํฉ๋๋ค. - ์๋ ์ ํ: ๋จ์ฉ ๋ฐ ์๋น์ค ๊ฑฐ๋ถ ๊ณต๊ฒฉ์ ๋ฐฉ์งํ๊ธฐ ์ํด ๋ฉ์์ง ์ ์ก์ ์๋ ์ ํ์ ๊ตฌํํฉ๋๋ค.
- ์ ๋ ฅ ์ ํจ์ฑ ๊ฒ์ฌ: ์ฃผ์ ๊ณต๊ฒฉ(์: ๊ต์ฐจ ์ฌ์ดํธ ์คํฌ๋ฆฝํ )์ ๋ฐฉ์งํ๊ธฐ ์ํด ์๋ฒ์์ ๋ชจ๋ ๋ค์ด์ค๋ ๋ฉ์์ง๋ฅผ ์ฒ ์ ํ ์ ํจ์ฑ ๊ฒ์ฌํฉ๋๋ค.
- ๋ฐ์ดํฐ ๊ฐ์ธ ์ ๋ณด ๋ณดํธ: ์ ์ธ๊ณ ๋ฐ์ดํฐ ๊ฐ์ธ ์ ๋ณด ๋ณดํธ ๊ท์ (์ ๋ฝ์ GDPR, ์บ๋ฆฌํฌ๋์์ CCPA, ์์์ ๋ฐ ๋ผํด ์๋ฉ๋ฆฌ์นด์ ๋ค์ํ ๊ตญ๊ฐ ๋ฒ๋ฅ ๋ฑ)์ ์ผ๋์ ๋์ญ์์ค. ํนํ ์ฑํ ์ ํ๋ฆฌ์ผ์ด์ ์ ๊ฒฝ์ฐ ๋ฐ์ดํฐ ์ฒ๋ฆฌ ํ๋ก์ธ์ค๋ฅผ ์ค์ํ๋๋ก ์ค๊ณํฉ๋๋ค.
- ํญ์ WSS(TLS/SSL) ์ฌ์ฉ: ์ ์ก ์ค์ธ ๋ฐ์ดํฐ๋ฅผ ๋ณดํธํ๊ธฐ ์ํด
- ๋ชจ๋ํฐ๋ง ๋ฐ ๊ด์ฐฐ ๊ฐ๋ฅ์ฑ:
- ์ค์๊ฐ ๋ชจ๋ํฐ๋ง: Prometheus, Grafana ๋๋ ํด๋ผ์ฐ๋ ๋ค์ดํฐ๋ธ ๋ชจ๋ํฐ๋ง ์๋น์ค์ ๊ฐ์ ๋๊ตฌ๋ฅผ ์ฌ์ฉํ์ฌ WebSocket ์๋ฒ์ ์ฑ๋ฅ(CPU, ๋ฉ๋ชจ๋ฆฌ, ํ์ฑ ์ฐ๊ฒฐ, ๋ฉ์์ง ์ฒ๋ฆฌ๋, ์ง์ฐ ์๊ฐ)์ ๋ชจ๋ํฐ๋งํฉ๋๋ค.
- ๋ถ์ฐ ์ถ์ : ์ฌ๋ฌ ์๋น์ค ๋ฐ ์ง์ญ์ ๊ฑธ์น ๋ฉ์์ง ํ๋ฆ์ ์ถ์ ํ์ฌ ๋ณต์กํ ์ํคํ ์ฒ์ ๋ฌธ์ ๋ฅผ ์ง๋จํ๋ ๋ฐ ๋์์ด ๋๋ ๋ถ์ฐ ์ถ์ ์ ๊ตฌํํฉ๋๋ค.
์ค์๊ฐ ํต์ ์ ๋ฏธ๋ ๋ํฅ
WebSocket์ ํ์ฌ ํ์ค์ด์ง๋ง ์ค์๊ฐ ํต์ ํ๊ฒฝ์ ๊ณ์ ๋ฐ์ ํ๊ณ ์์ต๋๋ค.
- WebTransport: Web Push ๋ฐ HTTP/3 ์ํ๊ณ์ ์ผ๋ถ์ธ WebTransport๋ ๋ถ์์ (๋ฐ์ดํฐ๊ทธ๋จ) ๋ฐ ์์ ์ (์คํธ๋ฆผ) ํต์ ์ QUIC๋ฅผ ํตํด ์ง์ํ์ฌ WebSocket๋ณด๋ค ๋ ๋ง์ ์ ์ฐ์ฑ์ ์ ๊ณตํฉ๋๋ค. WebSocket์ด ๋๋ฌด ๊ฒฝ์ง๋ ์ ์๋ ์ฌ์ฉ ์ฌ๋ก๋ฅผ ์ํด ๋ฎ์ ์ง์ฐ ์๊ฐ๊ณผ ๋ ๋์ ํผ์ก ์ ์ด๋ฅผ ์ ๊ณตํ๋๋ก ์ค๊ณ๋์์ผ๋ฉฐ, ํนํ ์ด๋ ค์ด ๋คํธ์ํฌ์์ ๊ทธ๋ ์ต๋๋ค. ๋ธ๋ผ์ฐ์ ๋ฐ ์๋ฒ ์ง์์ด ์ฑ์ํจ์ ๋ฐ๋ผ ํน์ ์ฌ์ฉ ์ฌ๋ก์ ๋งค๋ ฅ์ ์ธ ๋์์ด ๋ ์ ์์ต๋๋ค.
- ์๋ฒ๋ฆฌ์ค WebSockets: AWS API Gateway WebSockets, Azure Web PubSub ๋ฐ WebSockets๋ฅผ ์ฌ์ฉํ๋ Google Cloud Run๊ณผ ๊ฐ์ ํด๋ผ์ฐ๋ ๊ณต๊ธ์๋ ์ธ๊ธฐ๋ฅผ ์ป๊ณ ์์ต๋๋ค. ์ด๋ฌํ ์๋น์ค๋ ์ธํ๋ผ ๊ด๋ฆฌ๋ฅผ ์ถ์ํํ์ฌ ํนํ ๊ธ๋ก๋ฒ ๋ฐฐํฌ์ ์ผ๋ฐ์ ์ธ ๋ณ๋ํ๋ ํธ๋ํฝ ํจํด์ ๋ํด ๋งค์ฐ ํ์ฅ ๊ฐ๋ฅํ๊ณ ๋น์ฉ ํจ์จ์ ์ธ ์ค์๊ฐ ์ ํ๋ฆฌ์ผ์ด์ ์๋ฃจ์ ์ ์ ๊ณตํฉ๋๋ค.
- WebRTC ๋ฐ์ดํฐ ์ฑ๋: P2P ์ค์๊ฐ ํต์ ์ ๊ฒฝ์ฐ WebRTC ๋ฐ์ดํฐ ์ฑ๋์ ์ฐ๊ฒฐ์ด ์ค์ ๋๋ฉด ์ค์ ๋ฐ์ดํฐ ๊ตํ์ ์ํด ์๋ฒ๋ฅผ ์ฐํํ์ฌ ๋ธ๋ผ์ฐ์ ๊ฐ์ ์ง์ ์ ์ธ ๋ฎ์ ์ง์ฐ ์๊ฐ ๋งํฌ๋ฅผ ์ ๊ณตํฉ๋๋ค. ์ด๋ ํ์ ํ์ ๋ฐ ์จ๋ผ์ธ ๊ฒ์๊ณผ ๊ฐ์ด ์๋ฒ ์ธก ๋ฆด๋ ์ด๊ฐ ๋ถํ์ํ ์ง์ฐ ์๊ฐ์ ์ด๋ํ ์ ์๋ ์ ํ๋ฆฌ์ผ์ด์ ์ ์ด์์ ์ ๋๋ค.
๊ฒฐ๋ก
FastAPI์ ๊ฐ๋ ฅํ๊ณ ๋น๋๊ธฐ์ ์ธ WebSocket ์ง์์ ์ค์๊ฐ ํต์ ๊ธฐ๋ฅ์ ์น ์ ํ๋ฆฌ์ผ์ด์ ์ ํตํฉํ๋ ๋ฐ ํ์ํ๊ฒ ๊ฐ๋ ฅํ๊ณ ์ค์ฉ์ ์ธ ์ ํ์ ๋๋ค. ๊ณ ์ฑ๋ฅ, ๊ฐ๋ฐ์ ์นํ์ ์ธ ๊ตฌ๋ฌธ ๋ฐ ๊ฐ๋ ฅํ ํ์ ํํ ๊ธฐ๋ฅ์ ํ์ฅ ๊ฐ๋ฅํ๊ณ ์ ์ง ๊ด๋ฆฌํ๊ธฐ ์ฌ์ฐ๋ฉฐ ํจ์จ์ ์ธ ๋ฐฑ์๋ ์๋น์ค๋ฅผ ๋ง๋๋ ๊ฒฌ๊ณ ํ ๊ธฐ๋ฐ์ ์ ๊ณตํฉ๋๋ค.
WebSocket ํ๋กํ ์ฝ์ ๋ฏธ๋ฌํ ์ฐจ์ด๋ฅผ ์ดํดํ๊ณ , ์ฐ๊ฒฐ ๊ด๋ฆฌ, ๋ณด์ ๋ฐ ์ ์ญ ๊ณ ๋ ค ์ฌํญ์ ๊ฐ์ถ ํ์ฅ์ ์ํ ๊ฑด์ ํ ์ํคํ ์ฒ ํจํด์ ๊ตฌํํจ์ผ๋ก์จ FastAPI๋ฅผ ํ์ฉํ์ฌ ๋ชจ๋ ๋๋ฅ์ ์ฌ์ฉ์์๊ฒ ๋งค๋ ฅ์ ์ด๊ณ ์ฆ๊ฐ์ ์ธ ๊ฒฝํ์ ์ ๊ณตํ ์ ์์ต๋๋ค. ๊ฐ๋จํ ์ฑํ ์ ํ๋ฆฌ์ผ์ด์ , ๋ณต์กํ ํ์ ํ๋ซํผ ๋๋ ๋ผ์ด๋ธ ๋ฐ์ดํฐ ๋์๋ณด๋๋ฅผ ๊ตฌ์ถํ๋ FastAPI๋ฅผ ์ฌ์ฉํ๋ฉด ์ ์ญ ์ฌ์ฉ์์๊ฒ ์ค์๊ฐ์ผ๋ก ์ฐ๊ฒฐํ ์ ์์ต๋๋ค. ์ง๊ธ ๋ฐ๋ก FastAPI WebSockets๋ฅผ ์คํํ์ฌ ์ ํ๋ฆฌ์ผ์ด์ ์ ์๋ก์ด ์ฐจ์์ ์ํธ ์์ฉ์ ์ ๊ธ ํด์ ํ์ญ์์ค!